package com.gitee.wsl.io

import com.fleeksoft.io.ByteBufferFactory

interface Charset : Comparable<Charset> {

        fun name(): String

        fun decode(bb: ByteArray): CharSequence

        fun encode(cb: CharSequence): ByteArray

        companion object{
            val UTF8 by lazy { forName("UTF-8") }
            val US_ASCII by lazy { forName("US-ASCII") }
            val ISO_8859_1 by lazy { forName("ISO-8859-1") }
            val UTF_16 by lazy { forName("UTF-16") }
            val UTF_32 by lazy { forName("UTF-32") }
            val GB2312 by lazy { forName("GB2312") }

            fun forName(name: String): Charset = CharsetImp(com.fleeksoft.charset.Charsets.forName(name))

            fun isSupported(name: String): Boolean = com.fleeksoft.charset.Charsets.isSupported(name)
        }

}

class CharsetImp(val charset:com.fleeksoft.charset.Charset):Charset{

    override fun name(): String = charset.name()

    override fun decode(bb: ByteArray): CharSequence{//= base.decode(ByteBufferFactory.wrap(bb)).toString()
        val decode = charset.decode(ByteBufferFactory.wrap(bb))
        return decode.toString()
    }

    override fun encode(cb: CharSequence): ByteArray{//= charset.encode(CharBufferFactory.wrap(cb)).array()
        val result = charset.encode(cb.toString())
        val existingArray = when {
            result.hasArray() && result.arrayOffset() == 0 -> result.array().takeIf { it.size == result.remaining() }
            else -> null
        }
        return existingArray ?: ByteArray(result.remaining()).also { result.get(it) }
    }

    override fun toString(): String = charset.toString()

    override fun compareTo(other: Charset): Int {
        if( other !is CharsetImp) return 0
        return charset.compareTo(other.charset)
    }

}

fun ByteArray.decodeToString(charset: Charset = Charset.UTF8) = charset.decode(this).toString()

fun ByteArray.decodeToString(
    charset: Charset= Charset.UTF8,
    startIndex: Int=0,
    endIndex: Int = this.size,
    throwOnInvalidSequence: Boolean = false
) = charset.decode(this.copyOfRange(startIndex,endIndex)).toString()

fun CharSequence.encodeToByteArray(charset: Charset= Charset.UTF8) = charset.encode(this)

fun CharSequence.encodeToByteArray(
    charset: Charset= Charset.UTF8,
    startIndex: Int = 0,
    endIndex: Int = this.length,
    throwOnInvalidSequence: Boolean = false
): ByteArray = this.subSequence(startIndex, endIndex).encodeToByteArray(charset)

